#include "GameSession.h"
#include "LogEx.h"
#include "RobotUser.h"
#include "BasicServerEx.h"
#include "LoginMessage.pb.h"
#include "PlayerMessage.pb.h"
#include "RecruitMessage.pb.h"
#include "Utils.h"
using namespace SGLib;
using namespace std;

#include <google/protobuf/message_lite.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>

extern IServerEx *gsvr;

void CGameSocket::OnConnect(UserData &ud)
{
    u64 id = ud.u64d;
    const char *account = CRobotUserManager::Instance().GetAccount( id );
    LOG_DEBUG("[%s] connect game account[%s] id[%llu]", __FUNCTION__, account?account:"", id);
    if( account )
    {
        m_curUse = 0;
        m_account = account;
        m_loginTime = TIME_NOW;
        CRobotUserManager::Instance().UpdateRobot( m_account, this );
        m_curRecharge = CRobotUserManager::Instance().GetRecharge( m_account );
        // 连接游戏服成功 发送登录消息
        SendLogin();
    }
    else
    {
        Close();
    }
}

void CGameSocket::OnConnectError(UserData &ud)
{
    u64 id = ud.u64d;
    const char *account = CRobotUserManager::Instance().GetAccount( id );
    if( account )
    {
        CRobotUserManager::Instance().DestoryRobot( string(account) );
    }
}

void CGameSocket::OnClose()
{
    LOG_WARN("[%s] account[%s] 本次充值[%d] 本次消耗[%d] 当前元宝[%d]", 
        __FUNCTION__, m_account.c_str(), m_curRecharge, m_curUse, m_goldIngot );
    CRobotUserManager::Instance().DestoryRobot( m_account );
}

void CGameSocket::OnRecv(const byte *pkg, s32 len)
{
    google::protobuf::io::ArrayInputStream arrayInputStream(pkg, len);
    google::protobuf::io::CodedInputStream codedInputStream(&arrayInputStream);
    com::future::threekingdoms::server::transport::protocol::CommonMessage p;
    p.ParseFromCodedStream(&codedInputStream);
    LOG_DEBUG("[%s] account[%s] len[%d] msgid[%d]", __FUNCTION__, 
        m_account.c_str(), len, p.cmdid() );
    // 收到 -1001 消息后表示登录成功了 这时可以去获取 武将列表了
    switch( p.cmdid() )
    {
    case -1001:
        _LoginSuccess();
        break;
    case -1121:
        _WalletUpdate( p );
        break;
    case -5051:
        _RecvGeneralList( p );
        break;
    case -5073:
        _GeneralChangeResult( p );
        break;
    case -5061:
        _DrawGeneralList( p );
        break;
    default:
        LOG_WARN("[%s] recv unknown msg[%d]", __FUNCTION__, p.cmdid() );
        break;
    }
}

void CGameSocket::_Clean()
{
    m_account = "";
    m_hasLogin = false;
    m_generals.clear();
    m_generalIdx.clear();
    m_generalIdx2.clear();
    m_costGeneralList.clear();
    m_goldIngot = 0;
}

static s32 _GetMsgLen(byte *data, s32 len, s32 &msglen)
{
    static const int kMaxVarintBytes = 10;
    static const int kMaxVarint32Bytes = 5;
    const byte * ptr = data;
    u32 b;
    u32 result = 0;
    s32 headlen = 0;
    b = *(ptr++); result  = (b & 0x7F)      ; ++headlen; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) <<  7; ++headlen; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) << 14; ++headlen; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |= (b & 0x7F) << 21; ++headlen; if (!(b & 0x80)) goto done;
    b = *(ptr++); result |=  b         << 28; ++headlen; if (!(b & 0x80)) goto done;
    for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
        b = *(ptr++); if (!(b & 0x80)) goto done;
    }
    return 0;
done:
    msglen = result;
    return headlen;
}

void CGameSocket::_ProcessRecvData()
{
    const s32 MAX_INT32_LEN = 5;
    IPacketParser *parser = m_ioSockMgr->GetPacketParser();
    SELF_ASSERT( parser!=NULL, return; );

    // 使用google可变长度去解析 包长度的值 注意最多可能需要5个字节 最少一个字节
    byte tmpbuffer[E_MaxPkg_Len];// = {0};
    while(true)
    {
        // 尽量拷贝5个字节到一个临时数组里 去解析包长度
        s32 headlen = 0;
        s32 msglen = 0;
        s32 size = _GetRecvDataSize();
        s32 datalen1 = _GetRecvDataLen();
        byte *data1 = _GetRecvDataPtr();
        if( datalen1 >= MAX_INT32_LEN )
        {
            headlen = _GetMsgLen(data1, MAX_INT32_LEN, msglen);
        }
        else
        {
            byte tmphead[12] = {0};
            s32 tmplen = 0;
            if( size >= MAX_INT32_LEN )
            {
                tmplen = MAX_INT32_LEN;
                memcpy( tmphead, data1, datalen1 ); // 拷贝上半部分head
                memcpy( tmphead+datalen1, _GetRecvBuffer(), MAX_INT32_LEN-datalen1 ); // 拷贝下半部分head
            }
            else
            {
                tmplen = size;
                memcpy( tmphead, data1, datalen1 ); // 拷贝上半部分head
                memcpy( tmphead+datalen1, _GetRecvBuffer(), size-datalen1 ); // 拷贝下半部分head
            }
            headlen = _GetMsgLen(tmphead, tmplen, msglen);
        }
        LOG_DEBUG("====> headlen[%d] msglen[%d]", headlen, msglen);
        if( headlen == 0 )
            return; // 头部数据没有收全

        s32 totallen = (headlen + msglen);
        // 如果包大于最大包长度,直接忽略此包
        if( totallen > E_MaxPkg_Len || totallen <= 0 )
        {
            LOG_ERROR( "[%s][%s][%d] client[%d,%d] recv invalid msg. total[%d] headlen[%d] msglen[%d]", 
                    __FILE__, __FUNCTION__, __LINE__,
                    GetId(), m_socket, totallen, headlen, msglen );
            Close(); // 因为在worker线程中调用的
            return;
        }

        // 头部完整了 检查整个包是否完整
        if( size < (headlen + msglen) )
            return;

        // 找到一个完整包, 将包拷贝到tmpbuffer中
        byte *pkgdata = tmpbuffer;
        if( headlen < datalen1 )
        {
            if( totallen < datalen1 )
            {
                pkgdata = data1 + headlen;
            }
            else
            {
                s32 msgpart1 = datalen1 - headlen;
                memcpy( tmpbuffer, data1 + headlen, msgpart1 );
                memcpy( tmpbuffer+msgpart1, _GetRecvBuffer(), msglen - msgpart1 );
            }
        }
        else
        {
            pkgdata = _GetRecvBuffer() + (headlen - datalen1);
        }

        OnRecv( pkgdata, msglen );
        _ProcRecvDataSize( totallen );
    }
}

void CGameSocket::SendCommonMsg(com::future::threekingdoms::server::transport::protocol::CommonMessage &comMessage)
{
    // 根据消息提长度计算出整个发送长度
    int ackSize = comMessage.ByteSize();
    google::protobuf::uint8 target[4];
    google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(ackSize, target);
    ackSize = ackSize + sizeof (target);
    char* ackBuf = new char[ackSize];

    //write varint delimiter to buffer
    google::protobuf::io::ArrayOutputStream arrayOut(ackBuf, ackSize);
    google::protobuf::io::CodedOutputStream codedOut(&arrayOut);
    codedOut.WriteVarint32(comMessage.ByteSize());

    comMessage.SerializeToCodedStream(&codedOut);

    bool ret = Send((const byte*)ackBuf, codedOut.ByteCount());
    comMessage.release_data();
    delete[] ackBuf;

    LOG_DEBUG("[%s] account[%s] send msg[%d] len[%d] ret[%d]", __FUNCTION__, m_account.c_str(),
        (int)comMessage.cmdid(), (int)codedOut.ByteCount(), ret?1:0 );

    if( !ret )
    {
        Close();
    }
}

void CGameSocket::TryCostGoldIngot()
{
    // 准备消耗元宝
    s32 aftersec = (rand() % 3 + 2) * 1000;
    s32 tid = gsvr->AddTimer(aftersec, _timercall_CostGoldIngot, (void*)m_account.c_str(), m_account.length(), false);
    LOG_DEBUG( "[%s] account[%s] will cost goldingot aftersec[%d] tid[%d]", __FUNCTION__,
        m_account.c_str(), aftersec, tid );
}
void CGameSocket::_timercall_CostGoldIngot(void *pData, s32 nDataLen)
{
    if( nDataLen <= 0 )
    {
        LOG_ERROR("[%s]", __FUNCTION__);
        return;
    }

    string account((char*)pData, nDataLen);
    CGameSocket *session = (CGameSocket*)CRobotUserManager::Instance().GetSession( account );
    if( session )
    {
        session->CostGoldIngot();
    }
}
void CGameSocket::CostGoldIngot()
{
    if( m_generalIdx2.size() < 100 )
    {
        // 抽卡
        if( m_goldIngot >= 8800 )
        {
            // 可以10连抽
            DrawGenerals();
        }
        else
        {
            Close();
        }
    }
    else
    {
        // 卡片数量足够 先进行一轮 进化
        bool canevo = false;
        std::map<int, s64>::iterator it = m_generalIdx.begin();
        for( ; it != m_generalIdx.end(); ++it )
        {
            std::map<int, std::map<s64, com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg> >::iterator git = m_generals.find( it->first );
            if( git->second.size() > 1 )
            {
                // 可以进化
                std::map<s64, com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg>::iterator sit = git->second.begin();
                for( ; sit != git->second.end(); ++sit )
                {
                    if( sit->first == it->second )
                    {
                        continue; // 不能自己吃自己
                    }
                    if( sit->second.evolution() >= 20 )
                        continue; // 已经到最高级了
                    GeneralEvolution( it->second, sit->first, sit->second );
                    canevo = true;
                    goto _LABEL_END1;
                    break;
                }
            }
        }
_LABEL_END1://*/
        if( !canevo )
        {
            // 不能进化了 准备传功
            std::map<int, s64>::iterator it = m_generalIdx.begin();
            for( ; it != m_generalIdx.end(); ++it )
            {
                std::map<int, std::map<s64, com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg> >::iterator git = m_generals.find( it->first );
                if( git != m_generals.end() )
                {
                    std::map<s64, com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg>::iterator sit = git->second.find( it->second );
                    if( sit != git->second.end() )
                    {
                        // 找到要准备传功的武将了
                        if( sit->second.currentquality() >= 50 )
                            continue; // 已经到头了

                        s64 targetid = it->second;
                        com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg target = sit->second;
                        // 找4个不在候选武将列表里的武将 用于传功
                        vector<s64> glst;
                        git = m_generals.begin();
                        for( ; git != m_generals.end(); ++git )
                        {
                            int modelid = git->first;
                            std::map<int, s64>::iterator tmpgit = m_generalIdx.find(modelid);
                            // 如果当前要加入的武将在候选武将中 则要排除 指定的候选武将
                            s64 exid = (tmpgit == m_generalIdx.end()) ? 0 : tmpgit->second; // 要排除的id
                            for( sit=git->second.begin(); sit!=git->second.end(); ++sit )
                            {
                                if( sit->first == exid ) continue;
                                glst.push_back( sit->first );
                                if( glst.size() >= 4 )
                                {
                                    // 可以传功了
                                    GeneralQuality( targetid, glst, target );
                                    canevo = true;
                                    goto _LABEL_END2;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
_LABEL_END2://*/
        if( !canevo )
        {
            LOG_DEBUG( "[%s] account[%s] curuse[%d] currecharge[%d] goldingot[%d]", __FUNCTION__,
                m_account.c_str(), m_curUse, m_curRecharge, m_goldIngot );
            // 又不能进化 又不能传功 下线
            if( m_curUse <= (m_curRecharge * 0.6) )
            {
                // 抽卡
                if( m_goldIngot >= 8800 )
                {
                    LOG_DEBUG( "[%s] account[%s] 不能传功进化 可以抽卡", __FUNCTION__,
                        m_account.c_str() );
                    // 可以10连抽
                    DrawGenerals();
                }
                else
                {
                    Close();
                }
            }
            else
            {
                Close();
            }
        }
    }
}

void CGameSocket::SendLogin()
{
    com::future::threekingdoms::server::transport::protocol::CommonMessage comMessage;
    comMessage.set_cmdid(1001);

    com::future::threekingdoms::server::transport::protocol::Req1001 message2;

    u64 roleid = CRobotUserManager::Instance().GetRoleId( m_account );
    u64 userid = CRobotUserManager::Instance().GetUserId( m_account );
    string sessionid = CRobotUserManager::Instance().GetSessionId( m_account ); 

    message2.set_roleid(roleid);
    char* stringUserid = new char[10];
    sprintf(stringUserid,"%llu", userid);
    message2.set_passportid(stringUserid);
    delete [] stringUserid;

    message2.set_sessionid(sessionid);

    message2.set_viewwidth(1280);
    message2.set_viewheight(720);

    message2.set_mac(m_account);

    message2.set_os(1);
    message2.set_platform("laoh");

    message2.set_reload(0);

    string msgData;
    message2.SerializeToString(&msgData);
    comMessage.set_data(msgData);

    SendCommonMsg( comMessage );
}

void CGameSocket::HeartBeat()
{
    com::future::threekingdoms::server::transport::protocol::CommonMessage comMessage;
    comMessage.set_cmdid(1000);
    SendCommonMsg( comMessage );

    // 检查是否超时了还没有登录成功
    u64 now = TIME_NOW;
    if( !m_hasLogin && (now - m_loginTime) > 600 )
    {
        Close();
    }
}

void CGameSocket::GetGeneralList(int page, int pagesz)
{
    com::future::threekingdoms::server::transport::protocol::CommonMessage comMessage;
    comMessage.set_cmdid(5051);

    com::future::threekingdoms::server::transport::protocol::Req5051 msg;
    msg.set_page(page);
    msg.set_pagesize( pagesz );
    msg.set_type(1);
    msg.set_generalid(0);
    string msgData;
    msg.SerializeToString(&msgData);
    comMessage.set_data(msgData);
    SendCommonMsg( comMessage );
}

void CGameSocket::GeneralEvolution(s64 gid, s64 eatid, com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg &g)
{
    m_action = E_Action_Evolution;
    m_costGeneralList.clear();
    m_costGeneralList.insert( eatid );

    com::future::threekingdoms::server::transport::protocol::CommonMessage comMessage;
    comMessage.set_cmdid(5057);

    com::future::threekingdoms::server::transport::protocol::Req5057 msg;
    msg.set_generalid(gid);
    msg.set_eatgeneralid( eatid );
    string msgData;
    msg.SerializeToString(&msgData);
    comMessage.set_data(msgData);
    SendCommonMsg( comMessage );
    LOG_INFO("[%s] account[%s] 进化 evolution [%s][%d] gid[%lld] eat[%lld] quality[%d,%d] evolution[%d,%d]", 
        __FUNCTION__, m_account.c_str(),
        g.name().c_str(), g.modelid(), gid, eatid,
        g.currentquality(), g.qualityexp(),
        g.evolution(), g.evolutionexp() );
}

void CGameSocket::GeneralQuality(s64 gid, std::vector<s64> &eatid, com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg &g)
{
    m_action = E_Action_Quality;
    m_costGeneralList.clear();
    char streatid[512] = {0};
    for( size_t i=0; i<eatid.size(); ++i )
    {
        sprintf( streatid, "%s,%lld", streatid, eatid[i] );
        m_costGeneralList.insert( eatid[i] );
    }

    com::future::threekingdoms::server::transport::protocol::CommonMessage comMessage;
    comMessage.set_cmdid(5058);

    com::future::threekingdoms::server::transport::protocol::Req5058 msg;
    msg.set_generalid(gid);
    for( size_t i=0; i<eatid.size(); ++i )
    {
        msg.add_eatgeneralid( eatid[i] );
    }
    string msgData;
    msg.SerializeToString(&msgData);
    comMessage.set_data(msgData);
    SendCommonMsg( comMessage );
    LOG_INFO("[%s] account[%s] 传功 Quality gid[%lld] eat[%s] quality[%d,%d] evolution[%d,%d]", 
        __FUNCTION__, m_account.c_str(),
        gid, streatid,
        g.currentquality(), g.qualityexp(),
        g.evolution(), g.evolutionexp() );
}

void CGameSocket::DrawGenerals()
{
    m_action = E_Action_Other;
    m_costGeneralList.clear();

    com::future::threekingdoms::server::transport::protocol::CommonMessage comMessage;
    comMessage.set_cmdid(5061);

    com::future::threekingdoms::server::transport::protocol::ReqRecruit5061 msg;
    msg.set_actiontype( com::future::threekingdoms::server::transport::protocol::TEN_TIMES );
    msg.set_recruittype( com::future::threekingdoms::server::transport::protocol::GOLD );
    string msgData;
    msg.SerializeToString(&msgData);
    comMessage.set_data(msgData);
    SendCommonMsg( comMessage );
    LOG_INFO("[%s] account[%s] 10连抽", 
        __FUNCTION__, m_account.c_str() );
}

void CGameSocket::_LoginSuccess()
{
    m_hasLogin = true;
    LOG_INFO("[%s] account[%s] login success", __FUNCTION__, m_account.c_str() );

    m_page = 0;
    m_generals.clear();
    m_goldIngot = 0;
    m_action = E_Action_Other;
    m_curUse = 0;
    m_costGeneralList.clear();
    GetGeneralList( m_page, E_GeneralList_PageSize );
}

void CGameSocket::_WalletUpdate(com::future::threekingdoms::server::transport::protocol::CommonMessage &cm)
{
    com::future::threekingdoms::server::transport::protocol::Push1121 bean;
    bean.ParseFromString(cm.data());
    if( bean.has_wallet() )
    {
        int old = m_goldIngot;
        int change = (m_goldIngot > 0) ? (m_goldIngot - bean.wallet().goldingot()) : 0;
        m_curUse += change;
        m_goldIngot = bean.wallet().goldingot();
        LOG_INFO("[%s] account[%s] 旧值[%d] 当前元宝 goldingot[%d] 消耗了[%d][%d]", __FUNCTION__, 
            m_account.c_str(), old, m_goldIngot, change, m_curUse);
    }
}

void CGameSocket::_RecvGeneralList(com::future::threekingdoms::server::transport::protocol::CommonMessage &cm)
{
    com::future::threekingdoms::server::transport::protocol::Resp5051 bean;
    bean.ParseFromString(cm.data());

    int sz = (int)bean.generals_size();
    for ( int i = 0; i<sz; ++i )
    {
        const com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg &g = bean.generals(i);
        LOG_DEBUG("[%s] id[%lld] name[%s] rare[%d] quality[%d,%d] evolution[%d,%d] modelid[%d]", __FUNCTION__, 
            g.id(), g.name().c_str(), g.rare(),
            g.currentquality(), g.qualityexp(),
            g.evolution(), g.evolutionexp(), g.modelid() );

        m_generals[ g.modelid() ][ g.id() ] = g;
        m_generalIdx2[ g.id() ] = g.modelid();

        // 筛选出要传功和进化的对象 4星 5星 武将最小id的为目标对象
        std::map<int, s64>::iterator it = m_generalIdx.find( g.modelid() );
        if( g.rare()>=4 && (it == m_generalIdx.end() || g.id() < it->second) )
        {
            m_generalIdx[ g.modelid() ] = g.id();
            LOG_INFO("[%s] 找到一个目标 [%s][%d][%lld] quality[%d,%d] evolution[%d,%d]", __FUNCTION__,
                g.name().c_str(), g.modelid(), g.id(),
                g.currentquality(), g.qualityexp(),
                g.evolution(), g.evolutionexp() );
        }
    }
    if( sz == E_GeneralList_PageSize )
    {
        ++m_page;
        GetGeneralList( m_page, E_GeneralList_PageSize );
    }
    else
    {
        // 最后一页了
        // 准备消耗, 抽卡 武将进化 武将传功
        LOG_DEBUG("[%s] account[%s] 总共有[%d]个武将", __FUNCTION__, m_account.c_str(), (int)m_generalIdx2.size() );
        TryCostGoldIngot();
    }
}

void CGameSocket::_GeneralChangeResult(com::future::threekingdoms::server::transport::protocol::CommonMessage &cm)
{
    com::future::threekingdoms::server::transport::protocol::Resp5073 bean;
    bean.ParseFromString(cm.data());
    //1 传功 2 进化 3 升级 4 出战休息 5 上阵下阵（武将界面）0：其他
    char straction[6][32] = {
        "其他", "传功", "进化", "升级", "出战休息", "上陈下阵"
    };
    if( bean.cause() == m_action )
    {
        int ret = bean.error().code();
        string errmsg = bean.error().msg();
        if( ret == 0 )
        {
            LOG_INFO("[%s] account[%s] [%s] 成功", __FUNCTION__, 
                m_account.c_str(), straction[m_action] );
            // 更新武将
            int sz = (int)bean.generalbase_size();
            for ( int i = 0; i<sz; ++i )
            {
                const com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg &g = bean.generalbase(i);
                m_generals[ g.modelid() ][ g.id() ] = g;
                LOG_INFO("[%s] 更新了武将 [%d][%s] [%lld] quality[%d,%d] evolution[%d,%d]", __FUNCTION__, 
                    g.modelid(), g.name().c_str(), g.id(),
                    g.currentquality(), g.qualityexp(),
                    g.evolution(), g.evolutionexp() );
            }
            // 删除已吃掉的武将
            _RemoveCostGeneralList();

            if( (rand()%3 == 0) && m_curUse >= (m_curRecharge * 0.6) )
            {
                // 30%概率 如果消耗已经达到本次充值金额的60% 则可以下线了
                Close();
                return;
            }
            // 准备下一次消耗
            TryCostGoldIngot();
        }
        else
        {
            LOG_INFO("[%s] account[%s] [%s] 失败 [%s]", __FUNCTION__, 
                m_account.c_str(), straction[m_action], errmsg.c_str() );
            // 更新失败 一般是没元宝了 下线
            Close();
        }
    }
    else
    {
        LOG_ERROR("[%s] case[%d] error[%d][%s]", __FUNCTION__,
            bean.cause(), bean.error().code(), bean.error().msg().c_str() );
        Close();
    }
}

void CGameSocket::_RemoveCostGeneralList()
{
    char strlst[512] = {0};
    std::set<s64>::iterator it = m_costGeneralList.begin();
    for( ; it != m_costGeneralList.end(); ++it )
    {
        sprintf( strlst, "%s,%lld", strlst, *it );
        s64 id = *it;
        std::map<s64, int>::iterator git = m_generalIdx2.find( id );
        if( git != m_generalIdx2.end() )
        {
            int modelid = git->second;
            m_generalIdx2.erase( git );

            std::map<int, std::map<s64, com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg> >::iterator it1 = m_generals.find( modelid );
            if( it1 != m_generals.end() )
            {
                std::map<s64, com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg>::iterator it2 = it1->second.find( id );
                if( it2 != it1->second.end() )
                {
                    it1->second.erase( it2 );
                }
            }
        }
    }
    m_costGeneralList.clear();
    LOG_INFO("[%s] account[%s] remove gid[%s]", __FUNCTION__,
        m_account.c_str(), strlst );
}

void CGameSocket::_DrawGeneralList(com::future::threekingdoms::server::transport::protocol::CommonMessage &cm)
{
    com::future::threekingdoms::server::transport::protocol::ResRecruit5061 bean;
    bean.ParseFromString(cm.data());
    if( bean.type() == com::future::threekingdoms::server::transport::protocol::TEN_TIMES )
    {
        // 武将加入到列表中
        for (int i = 0;i<bean.generals_size();++i)
        {
            const com::future::threekingdoms::server::transport::protocol::GeneralDetail &gd = bean.generals(i);
            com::future::threekingdoms::server::transport::protocol::GeneralBaseMsg g;
            g.set_id( gd.generalid() );
            g.set_rare( gd.rare() );
            g.set_evolution( gd.evolution() );
            g.set_currentquality( gd.currentquality() );
            g.set_qualityexp( gd.qualityexp() );
            g.set_evolutionexp( gd.evolutionexp() );
            g.set_modelid( gd.modelid() );
            g.set_name( gd.activerole().rolebase().name() );

            LOG_DEBUG("[%s] 抽卡武将 id[%lld] name[%s] rare[%d] quality[%d,%d] evolution[%d,%d] modelid[%d]", __FUNCTION__, 
                g.id(), g.name().c_str(), g.rare(),
                g.currentquality(), g.qualityexp(),
                g.evolution(), g.evolutionexp(), g.modelid() );

            m_generals[ g.modelid() ][ g.id() ] = g;
            m_generalIdx2[ g.id() ] = g.modelid();
            // 筛选出要传功和进化的对象 4星 5星 武将最小id的为目标对象
            std::map<int, s64>::iterator it = m_generalIdx.find( g.modelid() );
            if( g.rare()>=4 && (it == m_generalIdx.end() || g.id() < it->second) )
            {
                m_generalIdx[ g.modelid() ] = g.id();
                LOG_INFO("[%s] 找到一个目标 [%s][%d][%lld] quality[%d,%d] evolution[%d,%d]", __FUNCTION__,
                        g.name().c_str(), g.modelid(), g.id(),
                        g.currentquality(), g.qualityexp(),
                        g.evolution(), g.evolutionexp() );
            }
        }

        // 准备下一次消耗
        TryCostGoldIngot();
    }
    else
    {
        LOG_ERROR("[%s] account[%s] known type[%d]", __FUNCTION__,
            m_account.c_str(), bean.type() );
    }
}


